#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
int NoeudSeqInst::getValeur() {
  int valeur=0;
  for (unsigned int i=0; i<tabInst.size(); i++)
    valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
  for (unsigned int i=0; i<tabInst.size(); i++)
    tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
  tabInst.push_back(instruction);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
  this->variable=variable;
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudAffectation::getValeur() {
  int valeur = expression->getValeur(); // on évalue l'expression
  ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudAffectation::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Affectation" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
  expression->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
                                               Noeud* operandeGauche,
                                               Noeud* operandeDroit) {
  this->operateur=operateur;
  this->operandeGauche=operandeGauche;
  this->operandeDroit=operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////
int NoeudOperateurBinaire::getValeur() { 
  int valeur=0;
  int og=operandeGauche->getValeur();
  int od=operandeDroit->getValeur();
  if      (this->operateur=="+") valeur = og+od; 
  else if (this->operateur=="-") valeur = og-od;
  else if (this->operateur=="*") valeur = og*od; 
  else if (this->operateur=="=="){
      if (og==od)
          valeur=1;
      else valeur=0;
  }
  else if (this->operateur=="!="){
       if (og==od)
          valeur=0;
      else valeur=1;
  }
  else if (this->operateur=="<"){
       if (og<od)
          valeur=1;
      else valeur=0;
  }
  else if (this->operateur==">"){
       if (og<od)
          valeur=0;
      else valeur=1;
  }
  else if (this->operateur=="<="){
       if (og<=od)
          valeur=1;
      else valeur=0;
  }
  else if (this->operateur==">="){
       if (og<=od)
          valeur=0;
      else valeur=1;
  }
  else if (this->operateur=="ou"){
      if (og==1 || od==1)
          valeur=1;
      else valeur=0;
}
else if (this->operateur=="et"){
      if (og==1 && od==1)
          valeur=1;
      else valeur=0;
}
else if (this->operateur=="non"){
    if (od==0)
        valeur=1;          
}
  else  // this->operateur=="/"
	if (od!=0)
		valeur = og/od;
  	else {
	  	cout << "Erreur pendant l'interpretation : division par zero" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  
  
  return valeur;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudOperateurBinaire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
  operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////

NoeudInstSi::NoeudInstSi(Noeud* expBool, Noeud* seqInst,Noeud* instSi,typeCondition typeC){
    this->instSi=instSi;
    this->expBool=expBool;
    this->seqInst=seqInst;
    this->typeC=typeC;
}
////////////////////////////////////////////////////////////////////////////////
void NoeudInstSi::afficher(unsigned short indentation){
        Noeud::afficher(indentation);
        cout << "Noeud - Instruction si "<<endl;
        expBool->afficher(indentation+1);
        seqInst->afficher(indentation+1);
        if(instSi!=NULL)
                instSi->afficher(indentation+1);
        
 }
////////////////////////////////////////////////////////////////////////////////
void NoeudInstSi::setInstSi(Noeud* siSuivant)
{
    this->instSi=siSuivant;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudInstSi::getValeur(){
        int valeur=NULL;
        if(this->expBool && ((int)expBool->getValeur()) == 1)
        {
            valeur=this->seqInst->getValeur();
        }
        else if(instSi!=NULL)
                valeur=this->instSi->getValeur();
        
        return valeur;
       
}
////////////////////////////////////////////////////////////////////////////////

NoeudTq::NoeudTq(Noeud* expBool, Noeud* seqInst){
    this->expBool=expBool;
    this->seqInst=seqInst;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudTq::getValeur()
{
    
        int valeur= 0;
        while((this->expBool->getValeur())==1)      
        {
           valeur=this->seqInst->getValeur();
       }
        return valeur;
}
    
    

////////////////////////////////////////////////////////////////////////////////

void NoeudTq::afficher(unsigned short indentation)
{
    
        Noeud::afficher(indentation);
        cout << "Noeud - Instruction tantque "<<endl;
        this->expBool->afficher(indentation+1);
        this->seqInst->afficher(indentation+1);
}
   

////////////////////////////////////////////////////////////////////////////////
    NoeudRep::NoeudRep(Noeud* expBool, Noeud* seqInst)
{
    this->expBool=expBool;
    this->seqInst=seqInst;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudRep::getValeur()
{
        int valeur=NULL;
        do
        {
            valeur=seqInst->getValeur();
        }
        while((this->expBool->getValeur())!=1);
        return valeur;
   
}
////////////////////////////////////////////////////////////////////////////////
void NoeudRep::afficher(unsigned short indentation)
{    
        Noeud::afficher(indentation);
        cout << "Noeud - Instruction repeter "<<endl;
        this->seqInst->afficher(indentation+1);
        this->expBool->afficher(indentation+1);   
}
////////////////////////////////////////////////////////////////////////////////
NoeudPr:: NoeudPr(Noeud* affectation1, Noeud* expBool, Noeud* affectation2, Noeud* seqInst)
{
    this->affectation1=affectation1;
    this->affectation2=affectation2;
    this->expBool=expBool;
    this->seqInst=seqInst;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudPr::getValeur()
{
    
        int valeur= 0;
//        affectation1->getValeur();
//        cout << expBool->getValeur();
//        while (expBool->getValeur()){
//            cout << "valeur : " << valeur;
//           valeur= seqInst->getValeur();
//           affectation2->getValeur();
//        }
        for(this->affectation1->getValeur();(this->expBool->getValeur())==1;this->affectation2->getValeur()){
           valeur=this->seqInst->getValeur();
        }
        return valeur;
    
}
////////////////////////////////////////////////////////////////////////////////
void NoeudPr::afficher(unsigned short indentation)
{
    
        Noeud::afficher(indentation);
        cout << "Noeud - Instruction pour "<<endl;
        this->affectation1->afficher(indentation+1);
        this->expBool->afficher(indentation+1);
        this->affectation2->afficher(indentation+1);
        this->seqInst->afficher(indentation+1);
}
    
////////////////////////////////////////////////////////////////////////////////
NoeudEcrire::NoeudEcrire(Noeud* expression) {
  this->expression=expression;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudEcrire::getValeur() {
 
        int valeur = expression->getValeur(); // on évalue l'expression
        return valeur;
}

////////////////////////////////////////////////////////////////////////////////
void NoeudEcrire::afficher(unsigned short indentation) {
  
        Noeud::afficher(indentation);
        cout << "Noeud - Ecrire" << endl;
        expression->afficher(indentation+1); // on affiche l'expression a ecrire en augmentant l'indentation
}
////////////////////////////////////////////////////////////////////////////////
NoeudLire::NoeudLire(Noeud* variable) {
  this->variable=variable;
}
////////////////////////////////////////////////////////////////////////////////
int NoeudLire::getValeur() {
   
    
        int valeur= 0;
        // A finir
        ((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
        return valeur;
}
void NoeudLire::afficher(unsigned short indentation) {
    
        Noeud::afficher(indentation);
        cout << "Noeud - Lire" << endl;
        variable->afficher(indentation+1); // on affiche variable et expression
}